﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using LX.Core.ExceptionHanding;

namespace LX.ExceptionHanding
{
    public class ExceptionContext : IExceptionContext
    {
        private Dictionary<string, object> handlers = new Dictionary<string, object>();

        public void Register<T>(Action<T> handler) where T : Exception
        {
            string id = Math.Abs(typeof (T).GetHashCode()).ToString();
            if (!handlers.ContainsKey(id))
            {
                handlers.Add(id, handler);
            }
        } 

        private void processException(Exception exp)
        {
            string id = Math.Abs(exp.GetType().GetHashCode()).ToString();
            if (!handlers.ContainsKey(id))
            {
                DefaultHandler(exp);
            }
            else
            {
                var handler = handlers[id];
                try
                {
                    var action = (Action<Exception>) handler;
                    action(exp);
                }catch
                {
                    DefaultHandler(exp);
                }
            }
        }

        /// <summary>
        /// 默认处理方式
        /// </summary>
        /// <param name="exp"></param>
        public virtual void DefaultHandler(Exception exp)
        {
            Exception e = exp;
            while ((e is ICanBubble) || (e is TargetInvocationException))
            {
                if (e is TargetInvocationException)
                {
                    e = (e as TargetInvocationException).InnerException;
                }else if (e is ICanBubble)
                {
                    e = (e as ICanBubble).GetBubbleException();
                }
            }
            throw e;
        }


        public void Handler(Exception exception)
        {
            processException(exception);
        }
    }
}
